package com.weimin;

import cn.hutool.json.JSONUtil;
import com.weimin.model.ClientInfoModel;
import com.weimin.model.MessageModel;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public class NatServer {
    private static final int SERVER_PORT = 15321;
    private static final Map<String, ClientInfoModel> clients = new ConcurrentHashMap<>();

    public static void main(String[] args) throws Exception {
        startUdpServer();
    }

    public static void startUdpServer() throws Exception {
        try (DatagramSocket serverSocket = new DatagramSocket(SERVER_PORT);) {
            System.out.println("UDP协调服务器已启动，监听端口: " + SERVER_PORT);
            byte[] receiveData = new byte[1024];
            while (true) {
                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                serverSocket.receive(receivePacket);
                String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
                InetAddress clientIp = receivePacket.getAddress();
                int clientPort = receivePacket.getPort();
                System.out.println("收到来自 " + clientIp + ":" + clientPort + " 的消息: " + message);
                handleClientMessage(message, clientIp, clientPort, serverSocket);
            }
        }
    }

    private static void handleClientMessage(String message, InetAddress clientIp, int clientPort,
                                            DatagramSocket serverSocket) throws IOException {
        if (!JSONUtil.isTypeJSON(message)) {
            System.out.println("异常数据 " + message);
            return;
        }
        MessageModel messageModel = JSONUtil.toBean(message, MessageModel.class);
        if (messageModel.getType() == null) {
            System.out.println("空类型数据 " + message);
            return;
        }
        switch (messageModel.getType()) {
            case "REGISTER":
                clients.put(messageModel.getClientId(), new ClientInfoModel(clientIp, clientPort));
                sendResponse(serverSocket, clientIp, clientPort, "REGISTER_OK 注册成功，你的ID: " + messageModel.getClientId());
                System.out.println("客户端 " + messageModel.getClientId() + " 已注册，地址: " + clientIp + ":" + clientPort);
                break;
            case "PAIR":
                // 验证目标客户端是否已注册
                ClientInfoModel targetInfo = clients.get(messageModel.getTargetId());
                if (targetInfo == null) {
                    sendResponse(serverSocket, clientIp, clientPort, "ERROR 目标客户端不存在");
                    return;
                }
                // 获取请求者信息
                ClientInfoModel requesterInfo = clients.get(messageModel.getClientId());
                // 向请求者发送目标客户端地址
                MessageModel send1 = new MessageModel();
                send1.setType("PAIR_OK");
                send1.setTargetId(messageModel.getTargetId());
                send1.setTargetIp(targetInfo.getPublicIp().getHostAddress());
                send1.setTargetPort(targetInfo.getPublicPort());
                sendResponse(serverSocket, requesterInfo.getPublicIp(), requesterInfo.getPublicPort(), JSONUtil.toJsonStr(send1));
                // 向目标客户端发送请求者地址
                send1.setTargetId(messageModel.getClientId());
                send1.setTargetIp(requesterInfo.getPublicIp().getHostAddress());
                send1.setTargetPort(requesterInfo.getPublicPort());
                sendResponse(serverSocket, targetInfo.getPublicIp(), targetInfo.getPublicPort(), JSONUtil.toJsonStr(send1));
                System.out.println("已协调配对: " + messageModel.getClientId() + " <-> " + messageModel.getTargetId());
                break;
            default:
                System.out.println("未知类型数据 " + message);
                break;
        }
    }

    private static void sendResponse(DatagramSocket socket, InetAddress ip, int port, String message) throws IOException {
        System.out.println("发送数据到 " + ip + " 端口 " + port + " 数据 " + message);
        byte[] sendData = message.getBytes();
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
        socket.send(sendPacket);
    }
}
